package sfeir.gwt.ergosoom.client.profile;

import java.util.ArrayList;
import java.util.List;

import sfeir.gwt.ergosoom.client.ClientApi;
import sfeir.gwt.ergosoom.client.ClientApiAsync;
import sfeir.gwt.ergosoom.client.Messages;
import sfeir.gwt.ergosoom.client.model.Email;
import sfeir.gwt.ergosoom.client.model.Person;
import sfeir.gwt.ergosoom.client.model.Profile;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasAlignment;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.TextBox;

public class LoginDialog extends DialogBox implements ClickHandler, ChangeHandler, KeyDownHandler {
    private Messages message = GWT.create(Messages.class);
    
    private TextBox login, firsname, lastname, email;
    private Button okButton, newButton, signupButton, cancelButton;
    private PasswordTextBox passwd, passwd2;
    private HTML msg;
    private Profile profile;
    private FlexTable log;

    private boolean aliasCheck = false;
    private boolean emailCheck = false;
    private ClientApiAsync client;
    private HandlerRegistration loginHandler;

    public LoginDialog() {
        super(false, false);
        client = GWT.create(ClientApi.class);
        
        setText(message.connexion());
        log = new FlexTable();
        login = new TextBox();
        login.addKeyDownHandler(this);
        passwd = new PasswordTextBox();
        passwd.addKeyDownHandler(this);

        log.setWidget(1, 0, new HTML(message.login() + "<font color=red>*</font>"));
        log.setWidget(1, 1, login);
        log.setWidget(2, 0, new HTML(message.password() + "<font color=red>*</font>"));
        log.setWidget(2, 1, passwd);

        msg = new HTML(message.login_msg());
        log.setWidget(0, 0, msg);
        log.getCellFormatter().setHorizontalAlignment(2, 0, HasAlignment.ALIGN_LEFT);
        log.getFlexCellFormatter().setColSpan(0, 0, 2);

        okButton = new Button(message.connexion());
        okButton.addClickHandler(this);
        log.setWidget(3, 1, okButton);
        
        newButton = new Button(message.new_label());
        newButton.addClickHandler(this);
        log.setWidget(3, 0, newButton);

        add(log);
        center();
    }
    
    @Override
    public void onClick(ClickEvent event) {
        
        if (event.getSource() == okButton) {
            
            Boolean error = false;

            String lg = login.getText();
            String pw = passwd.getText();
            
            if (lg.isEmpty()) {
                login.addStyleName("form-input-error");
                error = true;
            }
            else {
                login.removeStyleName("form-input-error");
            }
            if (pw.isEmpty()) {
                passwd.addStyleName("form-input-error");
                error = true;
            }
            else  {
                passwd.removeStyleName("form-input-error");
            }
            if (!error) {
                if (msg != null)
                    msg.setText(message.authentificating());
                client.login(lg, pw, true, new AsyncCallback<Profile>() {
        
                    @Override
                    public void onFailure(Throwable caught) {
                        if (msg != null)
                            msg.setHTML(message.error_bad_login());
                    }
        
                    public void onSuccess(Profile result) {
                        if (result != null) {
                            profile = result;
                            hide ();
                        }
                    }
                });
            }
        }
        else if (event.getSource() == newButton) {
            changeToNewProfile();
        }
        else if (event.getSource() == cancelButton) {
            changeToLogin();
        }
        else if (event.getSource() == signupButton && !checkError()) {
            signupButton.setEnabled(false);
            Profile p = new Profile(firsname.getText(), lastname.getText(), email.getText());
            List<Email> list = new ArrayList<Email>();
            list.add(new Email(email.getText()));
            p.getPerson().setEmails(list);
            p.setAlias(login.getText());
            p.setPassword(passwd.getText());
            client.signup(p,  new AsyncCallback<Profile>() {
                
                @Override
                public void onFailure(Throwable caught) {
                    if (msg != null) {
                        signupButton.setEnabled(false);
                        msg.setHTML(message.failure(caught.getMessage())); //TODO More explicite msg
                    }
                }
    
                public void onSuccess(Profile result) {
                    if (result != null) {
                        profile = result;
                        hide ();
                    }
                }
            });
        }
    }

    private Boolean checkError() {
        Boolean error = false;
        if (login.getText().isEmpty()) {
            login.addStyleName("form-input-error");
            login.setTitle(message.error_not_empty());
            error = true;
        }
        else if (aliasCheck) {
            login.removeStyleName("form-input-error");
            login.setTitle("");
        }
        if (email.getText().isEmpty()) {
            email.addStyleName("form-input-error");
            email.setTitle(message.error_not_empty());
            error = true;
        }
        else if (emailCheck) {
            email.removeStyleName("form-input-error");
            email.setTitle("");
        }
        if (lastname.getText().isEmpty()) {
            lastname.addStyleName("form-input-error");
            lastname.setTitle(message.error_not_empty());
            error = true;
        }
        else  {
            lastname.removeStyleName("form-input-error");
            lastname.setTitle("");
        }
        if (passwd.getText().isEmpty()) {
            passwd.addStyleName("form-input-error");
            passwd.setTitle(message.error_not_empty());
            error = true;
        }
        else  {
            passwd.removeStyleName("form-input-error");
            passwd.setTitle("");
        }
        if (passwd2.getText().isEmpty()) {
            passwd2.addStyleName("form-input-error");
            passwd2.setTitle(message.error_not_empty());
            error = true;
        }
        else  {
            passwd2.removeStyleName("form-input-error");
            passwd2.setTitle("");
        }
        if (!passwd.getText().equals(passwd2.getText())) {
            passwd2.addStyleName("form-input-error");
            passwd2.setTitle(message.error_pass_not_equal());
            error = true;
        }
        else  {
            passwd2.removeStyleName("form-input-error");
            passwd2.setTitle("");
        }
        if (!aliasCheck || !emailCheck) {
            error = true;
        }
        return error;
    }

    private void changeToNewProfile() {
        aliasCheck = false;
        signupButton = new Button(message.signup(), this);
        cancelButton = new Button(message.cancel(), this);
        loginHandler = login.addChangeHandler(this);
        onChangeAlias();
        setText(message.signup());
        passwd2 = new PasswordTextBox();
        firsname = new TextBox();
        lastname = new TextBox();
        email = new TextBox();
        email.addChangeHandler(this);
        log.setWidget(3, 0, new HTML(message.password() + "<font color=red>*</font>"));
        log.setWidget(3, 1, passwd2);
        log.setWidget(4, 0, new HTML(message.firstname()));
        log.setWidget(4, 1, firsname);
        log.setWidget(5, 0, new HTML(message.lastname() + "<font color=red>*</font>"));
        log.setWidget(5, 1, lastname);
        log.setWidget(6, 0, new HTML(message.email() + "<font color=red>*</font>"));
        log.setWidget(6, 1, email);
        log.setWidget(7, 1, signupButton);
        log.setWidget(7, 0, cancelButton);
    }
    
    private void changeToLogin() {
        aliasCheck = false;
        log.setWidget(3, 1, okButton);
        log.setWidget(3, 0, newButton);
        log.removeRow(7);
        log.removeRow(6);
        log.removeRow(5);
        log.removeRow(4);
        loginHandler.removeHandler();
        setText(message.connexion());
        login.removeStyleName("form-input-error");
        login.removeStyleName("form-input-ok");
        login.setTitle("");
        passwd.removeStyleName("form-input-error");
        passwd.setTitle("");
        msg.setHTML(message.login_msg());
    }
    
    @Override
    public void onChange(ChangeEvent event) {
        if (event.getSource() == login) {
            onChangeAlias();
        }
        if (event.getSource() == email) {
            onChangeEmail();
        }
    }
    
    public void onChangeEmail() {
        String value = email.getText();
        email.removeStyleName("form-input-error");
        email.setTitle("");
        emailCheck = false;
        if (!value.matches("^([a-z0-9_.+-])+@([a-z0-9_.+-])+$")) {
            email.addStyleName("form-input-error");
            return;
        }
    
        client.checkAlias(value, new AsyncCallback<Boolean>() {

            @Override
            public void onFailure(Throwable caught) {
                GWT.log(message.error_checkalias(), caught);
            }

            @Override
            public void onSuccess(Boolean result) {
                emailCheck = result;
                if (!result) {
                    email.setTitle(message.already_used());
                    email.addStyleName("form-input-error");
                }
            }

        });
    }
    
    public void onChangeAlias() {
        String value = login.getText();
        aliasCheck  = (profile != null && value.equals(profile.getAlias()));
        if (!value.matches("^([a-zA-Z0-9_.@+-])+$")) {
            login.addStyleName("form-input-error");
            login.setTitle(message.error_use_alphanum());
            aliasCheck = false;
            return;
        }
        if (!aliasCheck) {
            login.removeStyleName("form-input-error");
            login.removeStyleName("form-input-ok");
            client.checkAlias(value, new AsyncCallback<Boolean>() {

                @Override
                public void onFailure(Throwable caught) {
                    GWT.log(message.error_checkalias(), caught);
                }

                @Override
                public void onSuccess(Boolean result) {
                    aliasCheck = result;
                    if (result) {
                        login.setTitle(message.available());
                        login.removeStyleName("form-input-error");
                        login.addStyleName("form-input-ok");
                    } else {
                        login.setTitle(message.already_used());
                        login.addStyleName("form-input-error");
                    }
                }

            });
        }
    }

    public Person getPerson() {
        return profile.getPerson();
    }

    public void setPerson(Person person) {
        this.profile.setPerson(person);
    }

    public Profile getProfile() {
        return profile;
    }

    public void setProfile(Profile profile) {
        this.profile = profile;
    }

    @Override
    public void onKeyDown(KeyDownEvent event) {
        if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER && signupButton == null) {
            okButton.click();
        }
    }
}
